from db import db
from fvutil.managers import objectmanager
from fvutil import fvcon
from util import config
from presence import ps

import gobject
import random
import os

import logging.config
logging.config.fileConfig('logging.config')
logger = logging.getLogger('fluidvoice.tivo')

from controlmsgs import StartTivo, ExcludeFromTivo


class TivoPresence(ps.ObjectPresence):

    def __init__(self, oid, name):
        ps.ObjectPresence.__init__(self, oid, name)
    
    
class TivoManager(objectmanager.ObjectManager):
    
    __gsignals__ = {
            'sent_tivo' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT, gobject.TYPE_INT,)),
            'received_tivo' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_PYOBJECT,)),
            'warning_tivo' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT,)),
            'started_tivo' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                    (gobject.TYPE_INT,)),
            
    }
    
    ACTIVES = 17652
    OFFLINES = 17653
    
    def __init__(self, async, my_id, mixer, control):
        objectmanager.ObjectManager.__init__(self, fvcon.TIVO, my_id)
        self.__async = async
        self.__control = control
        self.__mixer = mixer
        self.__control.register_type_receiver(StartTivo, self.__on_recv_start_tivo)
        self.__control.register_type_receiver(ExcludeFromTivo, self.__on_recv_exclude_from_tivo)
        self.__path = config.get('async.folders', fvcon.TIVO)
        self.__my_id = my_id
        
        # tivo_id -> (user_ids, offline_user_ids, offline_user_ids, callback)
        self.__pending_tivos = {}
        # tivo_id -> (user_ids, offline_user_ids)
        self.__current_tivos = {}
        print 'TivoManager: Path - ',self.__path

        for detail in self.get_all():
            detail['status'] = fvcon.ONLINE
            print 'Adding input for',detail
            self.__mixer.onAddInput(self, detail)
        
    def send(self, data):
        logger.debug('Sending tivo with data %s', data)
        tivo_id = data['tivo_id']
        actives = data['actives']
        offlines = data['offlines']
        
        # TODO: tag with the usernames, not the user ids
        dests = actives + offlines
        
        actives = map(str, actives)
        offlines = map(str, offlines)
        tags = ','.join(actives + offlines)
        tivo_path = os.path.join(self.__path, str(tivo_id) + '.tivo')
        
        meta = {
                fvcon.TAGS: tags,
                TivoManager.ACTIVES : actives,
                TivoManager.OFFLINES : offlines,
                }
        
        header = self.__async.send_message(tivo_path, fvcon.TIVO, dests, meta)
        self.add(header)
        print 'Added tivo:',header.mid
        self.emit('sent_tivo', header.mid, fvcon.TIVO)
        
    def receive(self, header):
        logger.debug('Received tivo id %s', header.mid)
        self.add(header)
        flash = self.to_flash(header)
        self.emit('received_tivo', flash)
                
    def __on_recv_exclude_from_tivo(self, eft):
        user_id = eft.user_id
        tivo_id = eft.tivo_id
        logger.info('Received exclude_from_tv. user_id: %s, tivo_id: %s', user_id, tivo_id)
        if tivo_id in self.__pending_tivos:
            (user_ids, offline_user_ids, callback) = self.__pending_tivos[tivo_id]
            user_ids.remove(user_id)
            logger.debug('Removed user_id %s from pending tivo_id %s', user_id, tivo_id)
        else:
            logger.debug('Pending_tivos didnt have a tivo_id %s', tivo_id)
        
    # TODO: Abstract this. I'm doing the same thing twice.
    def __on_recv_start_tivo(self, st):
        user_ids = st.user_ids
        tivo_id = st.tivo_id
        logger.info('Received start_tivo. user_ids: %s, tivo_id: %s', user_ids, tivo_id)
        user_ids.remove(self.__my_id)
        self.on_start_tivo(None, tivo_id, user_ids , from_me=False)
        
    def on_start_tivo(self, obj, tivo_id, user_ids, from_me=True):
        logger.debug('on_start_tivo: %s', user_ids)
        offline_user_ids = []

        for user_id in user_ids:
                if not self.__control.is_neighbor(user_id):
                    offline_user_ids.append(user_id)
                else:
                    if from_me:
                        self.__control.send(StartTivo(tivo_id, user_ids + [self.__my_id]), user_id)
            
        # TODO: There must be sugar around this        
        for ou in offline_user_ids:
            user_ids.remove(ou)
            
        tivo_path = os.path.join(self.__path, str(tivo_id) + '.tivo')
        callback = gobject.timeout_add(config.get_int('fv', 'tivo-start-timeout-ms'), self.__on_do_start_tivo, tivo_id, tivo_path)
        self.__pending_tivos[tivo_id] = (user_ids, offline_user_ids, callback)
        print self.__pending_tivos[tivo_id]
        self.emit('warning_tivo', tivo_id)
        
    def on_stop_tivo(self, obj, tivo_id):
        logger.debug('on_stop_tivo: %s', tivo_id)
        self.__mixer.onStopTivo(self, tivo_id)
        (user_ids, offline_user_ids) = self.__current_tivos[tivo_id]
        del self.__current_tivos[tivo_id]
        data = {'tivo_id': tivo_id,
                'actives': user_ids,
                'offlines': offline_user_ids,
                }        
        self.send(data)

    
    def on_exclude_me_from_tivo(self, obj, tivo_id):
        logger.debug('on_exclude_from_tivo: %s', tivo_id)
        (callback, user_ids) = self.__pending_tivos[tivo_id]
        gobject.source_remove(callback)
        for user_id in user_ids:
            # Exclude me from all these people's TIVOs
            self.__control.send(ExcludeFromTivo(tivo_id, self.__my_id), user_id)
            
        
    def __on_do_start_tivo(self, tivo_id, tivo_path):
        logger.debug('__on_do_start_tivo: %s', tivo_id)
        (user_ids, offline_user_ids, callback) = self.__pending_tivos[tivo_id]
        logger.debug('About to start tivo with participating user_ids %s', user_ids)
        self.__mixer.onStartTivo(self, user_ids, tivo_id, tivo_path)
        del self.__pending_tivos[tivo_id]
        self.__current_tivos[tivo_id] = (user_ids, offline_user_ids)
        self.emit('started_tivo', tivo_id)
        
    def to_flash(self, header):
        return {'type':fvcon.TIVO, 
                'subcommand':fvcon.ADD, 
                'id':header.mid, 
                'label':header.meta[fvcon.TAGS],
                'tags':header.meta[fvcon.TAGS],
                'date':header.created,
                'authorID':header.src,
                'src':header.src,
                'local_path':header.get_file_path(),
                }